package com.wiscamp.ninechapters.problems.infrastructure.mappers.problems;

import com.wiscamp.ninechapters.problems.infrastructure.po.problems.ProblemView;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.List;

/**
 * 题视图仓储对象
 *
 * @author yifeng
 */
@Repository
public interface ProblemViewMapper extends JpaRepository<ProblemView, Long>, JpaSpecificationExecutor<ProblemView> {

    /**
     * 通过编号获取问题列表
     *
     * @param problemTypeId
     * @return
     */
    @Query(value = "select e from ProblemView e where e.problemTypeId = :problemTypeId and e.deleted = false")
    Collection<ProblemView> findListByProblemType(long problemTypeId);

    /**
     * 通过题集编号获取题列表
     *
     * @param collectionId
     * @return
     */
    @Query(value = "select e from ProblemView e where e.collectionId = :collectionId order by e.problemIndex asc")
    Collection<ProblemView> findListByCollection(long collectionId);

    /**
     * 通过题集编号获取题编号列表
     *
     * @param collectionId
     * @return
     */
    @Query(value = "select e.problemId from ProblemView e where e.collectionId = :collectionId order by e.problemIndex asc")
    Collection<Long> findProblemIdsByCollection(long collectionId);

    /**
     * 通过习题集编号获取题编号列表
     *
     * @param setId
     * @return
     */
    @Query(value = "select e.problemId from ProblemView e, SetProblemPO pt where pt.problemId = e.problemId and pt.setId = :setId and e.deleted = false order by pt.problemIndex asc")
    Collection<Long> findProblemIdsBySetId(long setId);

    /**
     * 通过题、部分和节编号获取题
     *
     * @param collectionId
     * @param partId
     * @param sectionId
     * @return
     */
    @Query(value = "select e from ProblemView e where e.collectionId = :collectionId and e.partId = :partId and e.sectionId =:sectionId order by e.problemIndex asc")
    Collection<ProblemView> findListByPartAndSection(long collectionId, long partId, long sectionId);

    /**
     * 分页获取题列表
     *
     * @param spec
     * @param pageable
     * @return
     */
    Page<ProblemView> findAll(Specification<ProblemView> spec, Pageable pageable);

    /**
     * 通过题编号列表获取按难度排序后的题列表
     *
     * @param problemIds
     * @return
     */
    @Query(value = "select e from ProblemView e where e.problemId in (:problemIds) order by e.difficulty asc")
    Collection<ProblemView> findListByProblemIdsOrderByDifficulty(Collection<Long> problemIds);

    /**
     * 通过题编号列表获取按难度排序后的题编号列表
     *
     * @param problemIds
     * @return
     */
    @Query(value = "select e.problemId from ProblemView e where e.problemId in (:problemIds) order by e.difficulty asc")
    Collection<Long> findProblemIdsByDifficultyAsc(Collection<Long> problemIds);


    @Query(value = "select i, s, pi, q, o, a, an from ProblemView i " +
            "left join StemPO s on i.problemId = s.problemId " +
            "inner join CollectionProblemPO pi on i.problemId = pi.problemId " +
            "inner join QuestionPO q on i.problemId = q.problemId " +
            "left join QuestionOptionPO o on q.problemId = o.problemId " +
            "inner join QuestionAnswerPO a on q.problemId = a.problemId " +
            "inner join QuestionSolutionPO an on q.problemId = an.problemId " +
            "where i.problemId = :problemId")
    List<Object[]> findCompositeProblem(long problemId);

    @Query(value = "select e.problemId from ProblemView e where e.problemId in (:problemIds) and e.difficulty between :startDifficulty and :endDifficulty and e.enabled = true")
    Collection<Long> findProblemIdsByDifficulty(Collection<Long> problemIds, int startDifficulty, int endDifficulty);

    @Query(value = "select pc.examId from ProblemView e, ProblemCollectionPO pc where e.collectionId = pc.collectionId and e.problemId = :problemId")
    long findExamIdByProblem(long problemId);
}
